%%%-------------------------------------------------------------------
%% @doc chat_queue public API
%% @end
%%%-------------------------------------------------------------------

%%%-------------------------------------------------------------------
%% 简单说明
%% 1. 缓存用的消息队列，消息
%% 2. 存储固定数量的消息，由 chat_save_message_max 配置
%% 3. fetch 固定数量的消息，由 chat_fetch_message_amount 配置
%% 4. 队列长度控制并不严谨
%% 5. 消息数据结构为 {id, body}
%% 6. 
%% 7. 
%% 8. 
%%%-------------------------------------------------------------------

-module(chat_queue).

-export([ in/3
        , fetch/3
        ]).

-export([ get_queue/1
        , set_queue/2
        , reset_queue/2
        ]).


%% 队列内放入消息，Max 长度由 chat_save_message_max 配置
in(Data, Msg, Max) ->
    {Len, Queue} = Data,
    len_max(Len + 1, queue:in(Msg, Queue), Max).

len_max(Len, Queue, Max) when Len > Max ->
    {_, Queue1} = queue:out(Queue),
    {Len - 1, Queue1};
len_max(Len, Queue, _Max) ->
    {Len, Queue}.


%% 从 Id 开始项后获取 Amount 条数据，Amount 由 chat_fetch_message_amount 配置
%% Id 为 0 时，从头开始获取
fetch(Data, Id, Amount) ->
    {_Len, Queue} = Data,
    do_fetch(Id, Amount, Queue).

do_fetch(Id, Amount, {QL, QR}) ->
    L1 = do_wash(Id, QL),
    L2 = do_wash(Id, lists:reverse(QR)),
    do_pack(Amount, L1, L2, []).

do_wash(0, List) -> List;
do_wash(_Id, []) -> [];
do_wash(Id, [{MId, _} | List]) when MId >= Id -> do_wash(Id, List);
do_wash(_Id, List) -> List.

do_pack(0, _L1, _L2, List) -> List;
do_pack(_Amount, [], [], List) -> List;
do_pack(Amount, [], [M | L2], List) -> do_pack(Amount-1, [], L2, [M | List]);
do_pack(Amount, [M | L1], L2, List) -> do_pack(Amount-1, L1, L2, [M | List]).


%%%-------------------------------------------------------------------
get_queue(Key) ->
    case erlang:get(Key) of
        undefined ->
            Queue = queue:new(),
            Len = 0,
            set_queue(Key, {Len, Queue}),
            {Len, Queue};
        {Len, Queue} ->
            {Len, Queue}
    end.

set_queue(Key, {Len, Queue}) ->
    erlang:put(Key, {Len, Queue}).

reset_queue(Data, BaseId) ->
    {_Len, Queue0} = Data,
    List = queue:to_list(Queue0),
    Len = erlang:length(List),
    QueueNew = queue:new(),
    F = fun
        ({_, Body}, {I, Queue}) ->
            {I + 1, queue:in({I, Body}, Queue)}
    end,
    {Id, Queue1} = lists:foldl(F, {BaseId, QueueNew}, List),
    {Id, {Len, Queue1}}.

